package cn.ac.iie.ulss.indexer.worker;

import cn.ac.iie.ulss.indexer.runenvs.Constants;
import cn.ac.iie.ulss.indexer.runenvs.GlobalParas;
import iie.metastore.MetaStoreClient;
import static java.lang.Thread.sleep;
import java.util.ArrayList;
import java.util.List;
import org.apache.hadoop.hive.metastore.api.Database;
import org.apache.hadoop.hive.metastore.api.FieldSchema;
import org.apache.hadoop.hive.metastore.api.Index;
import org.apache.hadoop.hive.metastore.api.Table;
import org.apache.log4j.Logger;

public class TableChange {

    public static Logger log = Logger.getLogger(TableChange.class.getName());

    public void createDB(String dbName) {
        MetaStoreClient msc = GlobalParas.clientPool.getClient();
        try {
            Database db = null;
            int num = 0;
            boolean getDBFlag = true;
            while (true) {
                try {
                    num++;
                    if (num == 3) {
                        getDBFlag = false;
                        break;
                    }
                    db = msc.client.getDatabase(dbName);
                    if (db != null) {
                        break;
                    }
                    sleep(10000);
                } catch (Exception e) {
                    log.error(e, e);
                    log.info("will load the DB again for " + num + "times");
                    sleep(10000);
                    continue;
                }
            }
            if (getDBFlag == true) {
                List<String> tbList = InitMetastoreInfo.getNewDB(dbName);
                for (String tbName : tbList) {
                    InitEnvCachedpara.initIndexinfo(dbName, tbName);
                    log.info("init the indexinfo ok after create the table:" + dbName + "." + tbName);
                }
                log.info("get DB ok for: " + db.getName());
            } else {
                log.info("get db failed!!!");
            }
        } catch (Exception ex) {
            log.error(ex, ex);
        } finally {
            GlobalParas.clientPool.realseOneClient(msc);
        }
    }

    public void deleteDB(String dbName) {
        MetaStoreClient msc = GlobalParas.clientPool.getClient();
        try {
            Database db = null;
            int num = 0;
            boolean getDBFlag = true;
            while (true) {
                db = null;
                try {
                    num++;
                    if (num == 3) {
                        getDBFlag = false;
                        break;
                    }
                    db = msc.client.getDatabase(dbName);
                    if (db == null) {
                        break;
                    }
                    sleep(10000);
                } catch (Exception e) {
                    log.error(e, e);
                    log.info("will load the db again for " + num + "times");
                    sleep(10000);
                    continue;
                }
            }
            if (getDBFlag == true) {
                List<String> tbList = GlobalParas.dbName2tableName.get(dbName);
                for (String tbName : tbList) {
                    dropTable(dbName, tbName);
                }
                GlobalParas.dbName2tableName.remove(dbName);
                log.info("delete DB ok for: " + dbName);
            } else {
                log.info("delete db failed!!!");
            }
        } catch (Exception ex) {
            log.error(ex, ex);
        } finally {
            GlobalParas.clientPool.realseOneClient(msc);
        }
    }

    public void createTable(String dbName, String tbName) {
        MetaStoreClient msc = GlobalParas.clientPool.getClient();
        try {
            Table tb = null;
            int num = 0;
            boolean getTableFlag = true;
            while (true) {
                try {
                    num++;
                    if (num == 3) {
                        getTableFlag = false;
                        break;
                    }
                    tb = msc.client.getTable(dbName, tbName);
                    if (tb != null) {
                        break;
                    }
                    sleep(10000);
                } catch (Exception e) {
                    log.error(e, e);
                    log.info("will load the table again for " + num + "times");
                    sleep(10000);
                    continue;
                }
            }
            if (getTableFlag == true) {
                GlobalParas.tablename2Table.put(dbName + "." + tbName, tb);
                if (GlobalParas.dbName2tableName.get(dbName) == null) {
                    List<String> list = new ArrayList<String>();
                    list.add(tbName);
                    GlobalParas.dbName2tableName.put(tbName, list);
                } else {
                    GlobalParas.dbName2tableName.get(dbName).add(tbName);
                }
                log.info("succeed to load the created table which is:" + tb.toString());
                List<Index> idxList = msc.client.listIndexes(dbName, tbName, (short) -1);
                GlobalParas.tablename2indexs.put(dbName + "." + tbName, idxList);
                log.info("get " + dbName + "." + tbName + " ok ");
                InitEnvCachedpara.initIndexinfo(dbName, tbName);
                log.info("init the indexinfo ok after create the table:" + dbName + "." + tbName);
            } else {
                log.info("get table failed!!!");
            }
        } catch (Exception ex) {
            log.error(ex, ex);
        } finally {
            GlobalParas.clientPool.realseOneClient(msc);
        }
    }

    public void dropTable(String dbName, String tbName) {
        GlobalParas.dbName2tableName.get(dbName).remove(tbName);
        GlobalParas.tablename2Table.remove(dbName + "." + tbName);
        GlobalParas.tablename2table2idx2LuceneFieldMap.remove(dbName + "." + tbName);
        GlobalParas.tablename2table2idx2LuceneFieldTypeMap.remove(dbName + "." + tbName);
        GlobalParas.tablename2table2idx2colMap.remove(dbName + "." + tbName);
        for (IndexControler c : GlobalParas.id2Createindex.values()) {
            if (c.dbName.equals(dbName) && c.tbName.equals(tbName)) {
                c.tableChangeFlag.getAndSet(Constants.TABLE_NORMAL_TIME);
            }
        }
        log.info("drop table ok:" + dbName + "." + tbName);
        log.info("the thread to write data begin");
    }

    public void changeTableName(String db_name, String tb_name, String old_tb_name) {
        MetaStoreClient msc = GlobalParas.clientPool.getClient();
        try {
            Table tb = null;
            int num = 0;
            boolean getTableFlag = true;
            while (true) {
                try {
                    num++;
                    if (num == 3) {
                        getTableFlag = false;
                        break;
                    }
                    tb = msc.client.getTable(db_name, tb_name);
                    if (tb != null) {
                        getTableFlag = true;
                        break;
                    }
                    sleep(10000);
                } catch (Exception e) {
                    log.error(e, e);
                    log.info("the table name has not been changed, will load the it again!");
                    sleep(10000);
                    continue;
                }
            }
            if (getTableFlag == true) {
                GlobalParas.tablename2Table.put(db_name + "." + tb_name, tb);
                GlobalParas.tablename2Table.remove(db_name + "." + old_tb_name);
                log.info("succeed to load the changed table which is:" + tb.toString());
                List<Index> idxList = msc.client.listIndexes(db_name, tb_name, (short) -1);
                GlobalParas.tablename2indexs.put(db_name + "." + tb_name, idxList);
                GlobalParas.tablename2indexs.remove(db_name + "." + old_tb_name);
                GlobalParas.tablename2table2idx2LuceneFieldMap.remove(db_name + "." + old_tb_name);
                GlobalParas.tablename2table2idx2LuceneFieldTypeMap.remove(db_name + "." + old_tb_name);
                GlobalParas.tablename2table2idx2colMap.remove(db_name + "." + old_tb_name);
                InitEnvCachedpara.initIndexinfo(db_name, tb_name);
                for (IndexControler c : GlobalParas.id2Createindex.values()) {
                    if (c.dbName.equals(db_name) && c.tbName.equals(old_tb_name)) {
                        c.tableChangeFlag.getAndSet(Constants.TABLE_NORMAL_TIME);
                    }
                }
                log.info("init the indexinfo ok after change name for the table:" + db_name + "." + tb_name);
            } else {
                log.info("get table failed!!!");
            }
        } catch (Exception ex) {
            log.error(ex, ex);
        } finally {
            GlobalParas.clientPool.realseOneClient(msc);
        }
    }

    public void columnDelete(String dbName, String tbName, String colName, String colType) {  //ok
        MetaStoreClient msc = GlobalParas.clientPool.getClient();
        try {
            Table tb = null;
            boolean bk = true;
            int num = 0;
            while (true) {
                bk = true;
                try {
                    num++;
                    if (num == 3) {
                        break;
                    }
                    tb = msc.client.getTable(dbName, tbName);
                    for (FieldSchema fc : tb.getSd().getCols()) {
                        if (fc.getName().equals(colName)) {
                            bk = false;
                            break;
                        }
                    }
                    if (bk == true) {
                        log.info("the column has been deleted,will break!");
                        break;
                    }
                    log.info("the column has not been deleted,will load the table again");
                    sleep(10000);
                } catch (Exception e) {
                    log.error(e, e);
                    log.info("the column has not been deleted,will load the table again");
                    sleep(10000);
                    continue;
                }
            }
            GlobalParas.tablename2Table.put(dbName + "." + tbName, tb);
            List<Index> idxList = msc.client.listIndexes(dbName, tbName, (short) -1);
            GlobalParas.tablename2indexs.put(dbName + "." + tbName, idxList);
            InitEnvCachedpara.initIndexinfo(dbName, tbName);
            log.info("init the indexinfo ok after create the table:" + dbName + "." + tbName);
        } catch (Exception ex) {
            log.error(ex, ex);
        } finally {
            GlobalParas.clientPool.realseOneClient(msc);
        }
    }

    public void columnAdd(String dbName, String tbName, String column_name, String column_type) {
        MetaStoreClient msc = GlobalParas.clientPool.getClient();
        try {
            Table tb = null;
            int num = 0;
            while (true) {
                try {
                    num++;
                    if (num == 3) {
                        break;
                    }
                    tb = msc.client.getTable(dbName, tbName);
                    if (tb.getSd().getCols().get(tb.getSd().getCols().size() - 1).getName().equals(column_name)) {
                        break;
                    }
                    log.info("the column has not been added,will load the table again");
                    sleep(10000);
                } catch (Exception e) {
                    log.error(e, e);
                    log.info("the column has not been added,will load the table again");
                    sleep(10000);
                    continue;
                }
            }
            GlobalParas.tablename2Table.put(dbName + "." + tbName, tb);
            log.info("get the updated table ok：" + dbName + "." + tbName + "->" + tb);
            List<Index> idxList = msc.client.listIndexes(dbName, tbName, (short) -1);
            GlobalParas.tablename2indexs.put(dbName + "." + tbName, idxList);
            InitEnvCachedpara.initIndexinfo(dbName, tbName);
            log.info("init the indexinfo ok after create the table:" + dbName + "." + tbName);
        } catch (Exception ex) {
            log.error(ex, ex);
        } finally {
            GlobalParas.clientPool.realseOneClient(msc);
        }
    }

    public void changeColumnName(String dbName, String tbName, String colName, String oldColName) {   //有问题
        MetaStoreClient msc = GlobalParas.clientPool.getClient();
        try {
            Table tb = null;
            int num = 0;
            while (true) {
                try {
                    num++;
                    if (num == 3) {
                        break;
                    }
                    boolean bk = false;
                    tb = msc.client.getTable(dbName, tbName);
                    for (FieldSchema fc : tb.getSd().getCols()) {
                        if (fc.getName().equals(colName)) {
                            log.info("colName:" + fc.getName());
                            bk = true;
                            break;
                        }
                    }
                    if (bk == true) {
                        log.info("the column has been renamed ok,will break!");
                        break;
                    } else {
                        log.info("the column has not been renamed ok,will try agian!");
                        sleep(10000);
                    }
                } catch (Exception e) {
                    log.error(e, e);
                    log.info("the column has not been renamed ok,will try agian!");
                    sleep(10000);
                    continue;
                }
            }
            GlobalParas.tablename2Table.put(dbName + "." + tbName, tb);
            log.info("get the updated table ok：" + dbName + "." + tbName + "->" + tb);
            List<Index> idxList = msc.client.listIndexes(dbName, tbName, (short) -1);
            GlobalParas.tablename2indexs.put(dbName + "." + tbName, idxList);
            InitEnvCachedpara.initIndexinfo(dbName, tbName);
            log.info("init the indexinfo ok after create the table:" + dbName + "." + tbName);
        } catch (Exception ex) {
            log.error(ex, ex);
        } finally {
            GlobalParas.clientPool.realseOneClient(msc);
        }
    }

    public void getIndex(String dbName, String tbName, String indexName) {
        MetaStoreClient msc = GlobalParas.clientPool.getClient();
        try {
            Table tb = msc.client.getTable(dbName, tbName);
            GlobalParas.tablename2Table.put(dbName + "." + tbName, tb);
            log.info("get " + dbName + "." + tbName + " ok ");
            Index index = null;
            int num = 0;
            while (true) {
                try {
                    num++;
                    if (num == 3) {
                        break;
                    }
                    index = msc.client.getIndex(dbName, tbName, indexName);
                    if (index != null) {
                        break;
                    }
                    sleep(10000);
                } catch (Exception e) {
                    log.info("the indexInfo has not been update,will load it again");
                    sleep(10000);
                    continue;
                }
            }
            List<Index> index1 = GlobalParas.tablename2indexs.get(dbName + "." + tbName);
            index1.add(index);
            GlobalParas.tablename2indexs.put(dbName + "." + tbName, index1);
            log.info("get the updated index ok：" + dbName + "." + tbName + "->" + index);
            InitEnvCachedpara.initIndexinfo(dbName, tbName);
            log.info("init the indexinfo ok after add the index:" + dbName + "." + tbName + "->" + indexName);
        } catch (Exception ex) {
            log.error(ex, ex);
        } finally {
            GlobalParas.clientPool.realseOneClient(msc);
        }
    }

    public void deleteIndex(String dbName, String tbName, String indexName) {
        MetaStoreClient msc = GlobalParas.clientPool.getClient();
        try {
            Table tb = msc.client.getTable(dbName, tbName);
            GlobalParas.tablename2Table.put(dbName + "." + tbName, tb);
            log.info("get " + dbName + "." + tbName + " ok ");
            int num = 0;
            while (true) {
                try {
                    num++;
                    if (num == 3) {
                        break;
                    }
                    if (msc.client.getIndex(dbName, tbName, indexName) == null) {
                        log.info("the index has been deleted, will break!");
                        break;
                    }
                    sleep(10000);
                } catch (Exception e) {
                    log.info("the index has not been deleted,will load it again");
                    sleep(10000);
                    continue;
                }
            }
            List<Index> indexList = msc.client.listIndexes(dbName, tbName, (short) -1);
            GlobalParas.tablename2indexs.put(dbName + "." + tbName, indexList);
            log.info("get the updated index ok：" + dbName + "." + tbName + "->" + indexName);
            InitEnvCachedpara.initIndexinfo(dbName, tbName);
            log.info("init the indexinfo ok after delete the index:" + dbName + "." + tbName + "->" + indexName);
        } catch (Exception ex) {
            log.error(ex, ex);
        } finally {
            GlobalParas.clientPool.realseOneClient(msc);
        }
    }
}
